地震発生地の可視化2 を改造し,深度の色範囲を変更してください.
回答例:
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
// map描画領域の設定
d3.select("#screen").attr("id","map").attr("style", "width: "+width+"px; height: "+height+"px;");
// mapの作成
var map = L.map('map').setView([35.70089,139.4300], 2);
// クレジット文字列
var credit = '<a href="http://portal.cyberjapan.jp/help/termsofuse.html">国土地理院</a>';
// 国土地理院のタイル
var tileurl = 'http://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png';
//タイルの設定
L.tileLayer(tileurl, {maxZoom: 18, attribution: credit,}).addTo(map);
// svgレイヤの初期化
// leflet v0.7.7以下の場合は以下
// map._initPathRoot();
// leflet v0.8以降
var layer = L.svg().addTo(map);
// 地図上のsvgレイヤにg要素を作る
var g = d3.select("#map").select("svg").append("g");
var url = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.csv"
d3.csv(url, function(error,data) {
var max = d3.max(data,function(a){return a.depth;});
var min = d3.min(data,function(b){return b.depth;});
var depth = d3.scale.linear().domain([min,max]).interpolate(d3.interpolateRgb).range(['#ffff00', '#ff0000'])
// csvファイルの緯度経度からLatLngオブジェクトを作成
data.forEach(function(d){
d.LatLngObj = new L.LatLng(d.latitude, d.longitude);
});
// g要素に円を描画する
var circle = g.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx",0)
.attr("cy",0)
.attr("r",10)
.attr("stroke","#0000ff")
.attr("stroke-width",2)
.attr("fill",function(d){return depth(d.depth);});
// 再描画用の関数を設定
// leflet v0.7.7以下の場合は以下
//map.on("viewreset", update);
// leflet v0.8以降
layer.on("update",update);
update();
// 再描画用関数
function update() {
// データの緯度経度を地図座標に変換
circle.attr("transform", function(d) {
var point = map.latLngToLayerPoint(d.LatLngObj);
return "translate("+ point.x+","+ point.y+")";
});
}
});
};
表示結果:
地震発生地の可視化2 を改造し,円の半径をマグニチュードで表現するようにしてください.
http://earthquake.usgs.gov/data/comcat/data-eventterms.php#mag
回答例:
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
// map描画領域の設定
d3.select("#screen").attr("id","map").attr("style", "width: "+width+"px; height: "+height+"px;");
// mapの作成
var map = L.map('map').setView([35.70089,139.4300], 2);
// クレジット文字列
var credit = '<a href="http://portal.cyberjapan.jp/help/termsofuse.html">国土地理院</a>';
// 国土地理院のタイル
var tileurl = 'http://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png';
//タイルの設定
L.tileLayer(tileurl, {maxZoom: 18, attribution: credit,}).addTo(map);
// svgレイヤの初期化
var layer = L.svg().addTo(map);
// 地図上のsvgレイヤにg要素を作る
var g = d3.select("#map").select("svg").append("g");
var url = "http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.csv"
d3.csv(url, function(error,data) {
var max = d3.max(data,function(a){return a.depth;});
var min = d3.min(data,function(b){return b.depth;});
// マグニチュードの最小値を取得するå
var min_mag = d3.min(data,function(d){return d.mag;});
// マグニチュードの最大値を取得する
var max_mag = d3.max(data,function(d){return d.mag;});
var depth = d3.scale.linear().domain([min,max]).interpolate(d3.interpolateRgb).range(['#b2cbe4', '#001e43'])
var mag = d3.scale.linear().domain([min_mag, max_mag]).range([1,10]);
// csvファイルの緯度経度からLatLngオブジェクトを作成
data.forEach(function(d){
d.LatLngObj = new L.LatLng(d.latitude, d.longitude);
});
// g要素に円を描画する
var circle = g.selectAll("circle")
.data(data)
.enter()
.append("circle")
.attr("cx",0)
.attr("cy",0)
.attr("r",function(d){return mag(d.mag);})
.attr("stroke","#0000ff")
.attr("stroke-width",2)
.attr("fill",function(d){return depth(d.depth);});
// 再描画用の関数を設定
layer.on("update", update);
update();
// 再描画用関数
function update() {
// データの緯度経度を地図座標に変換
circle.attr("transform", function(d) {
var point = map.latLngToLayerPoint(d.LatLngObj);
return "translate("+ point.x+","+ point.y+")";
});
}
});
};
表示結果:
前回は,アメリカ地質調査所(United States Geological Survey; USGS) Earthquake Hazards Program(https://earthquake.usgs.gov/earthquakes/)の地震観測データを題材にした d3.js による地理空間情報の可視化手法を学びました.具体的には,CSVファイルの処理手法および leaflet との連携による地図マッピング手法を学びました.
今回も前回に引き続き d3.js による地理空間情報の可視化手法を学びます. 具体的には,d3.js によるシェープファイル(Shapefile)の処理手法(実際は別ファイルフォーマットに変換して処理)を学びます.
シェープファイルとは,Esri社が提唱した地理情報システム(GIS)のためのファイルフォーマットです.シェープファイルは地理空間情報だけでなく,その属性情報も格納できるようになっています.e-Statの「地図で見る統計(統計GIS)」でも採用されているファイルフォーマットです.
シェープファイルはフォーマット仕様が公開されているため*,Esri社のソフトウェア以外からも処理することができます.しかしながら,シェープファイルは基本的にはバイナリ形式のファイルフォーマットであるため,JavaScriptでの処理には不向きです.
一方,テキストベースの地理空間情報ファイルフォーマットとして GeoJSON(http://geojson.org/) があります. GeoJSONは,JavaScriptのオブジェクト記述手法であるJSON(JavaScript Object Notation)を用いて地理空間情報である点や面,それに付随する属性情報を表現するファイルフォーマットです.JSONを採用しているので,JavaScriptのオブジェクトとしてGeoJSONファイルを処理することが可能です.
つまり,シェープファイルをGeoJSONファイルに変換すれば, d3.js で処理することが可能となります.
今回は統計GISより「平成22年国勢調査(小地域)国立市」のシェープファイルを入手します. すでに入手済みの場合は次の手順「シェープファイルからGeoJSONファイルへの変換」に進んでください.
e-Statの「地図で見る統計(統計GIS)」へアクセスします.
「データダウンロード」をクリックします.
「Step 1:統計調査(集計)を選択」では「国勢調査」>「平成22年国勢調査(小地域)2010/10/01」を選択します.「Step 2:統計表を選択(複数選択可能)」では「年齢別(5歳階級、4区分)、男女別人口」にチェックを入れて,「統計表各種データダウンロードへ」をクリックします.
「Step 3:地域選択」では「東京都」>「13215 国立市」を選択し, 「検索」をクリックします.
今回はシェープファイルだけの入手なので「世界測地系緯度経度・Shape形式」の「国立市(26KB)」をクリックし,シェープファイルをダウンロードします.
ダウンロードしたファイルはRの作業ディレクトリに移動し,展開してください.
シェープファイルをGeoJSONファイルに変換するための手法はいくつかありますが, ここではRを用いた変換手法を紹介します.
Rを起動し,下記パッケージを読み込みます.
if(!require(maptools)){
install.packages("maptools");
library(maptools);
}
if(!require(rgdal)){
install.packages("rgdal");
library(rgdal);
}「maptools」はシェープファイルの読み込み, 「rgdal」はGeoJSONの書き込みに使います.
それでは実際にシェープファイルからGeoJSONファイルにファイル変換する例を以下に示します.
# Shapefile の読み込み(ファイルパスは適宜変更すること)
shp <- maptools::readShapePoly("A002005212010DDSWC13215/h22ka13215.shp");
# 文字コード変換
shp@data$MOJI <- iconv(shp@data$MOJI,from="sjis",to="utf8");
shp@data$GST_NAME <- iconv(shp@data$GST_NAME,from="sjis",to="utf8");
shp@data$KEN_NAME <- iconv(shp@data$KEN_NAME,from="sjis",to="utf8");
# 座標系設定
sp::proj4string(shp) <- sp::CRS("+proj=longlat +datum=WGS84");
# ファイル出力
if(!file.exists("kunitachi.json")){
# GeoJSON形式で出力
rgdal::writeOGR(obj = shp,dsn = "kunitachi.json",layer = "kunitachi",driver="GeoJSON",check_exists = FALSE);
}上記コードを実行すると,作業ディレクトリにGeoJSON形式のファイルが保存されます.
それでは変換したGeoJSONファイルを d3.js を用いて表示してみましょう. d3.js にはいくつかの投影法が実装されていますが,ここではメルカトル図法を用います.
また,人口に応じて地域を塗り分けます.
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
var svg = d3.select("#screen")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
// GeoJSONデータの読み込み
d3.json("kunitachi.json", function(json) {
var projection,path;
// 投影関数定義(メルカトル図法)
projection = d3.geo.mercator()
.center(d3.geo.centroid(json))
.translate([width / 2, height / 2])
.scale(450000);
// 投影方法設定
path = d3.geo.path().projection(projection);
// 人口の最大値,最小値,中央値の取得
var max = d3.max(json.features,function(a){return a.properties.JINKO;})
var min = d3.min(json.features,function(a){return a.properties.JINKO;})
var median = d3.median(json.features,function(a){return a.properties.JINKO;})
// 塗り色で人口を表現するための正規化関数の定義
var colorScale = d3.scale.linear()
.domain([min,median,max])
.interpolate(d3.interpolateRgb).range(["#FFFFFF", "#FFFF00","#FF0000"]);
// 描画
svg.selectAll('path').data(json.features).enter()
.append('path')
.attr('d', path)
.attr("fill", function(d){ return colorScale(d.properties.JINKO);})
.attr("stroke",d3.rgb(0,0,0))
.on('mouseover', function(d){ /* mouseover event */ })
.on('mouseout', function(d){ /* mouseout event */ })
.on('click', function(d) {/* click event */ });
});
};
d3.js ではマウスイベントを処理することも可能です. 例えば,領域をクリックするとアラートが表示されるようにするには, 以下のようにコードを変更します.
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
var svg = d3.select("#screen")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
// GeoJSONデータの読み込み
d3.json("kunitachi.json", function(json) {
var projection,path;
// 投影関数定義(メルカトル図法)
projection = d3.geo.mercator()
.center(d3.geo.centroid(json))
.translate([width / 2, height / 2])
.scale(450000);
// 投影方法設定
path = d3.geo.path().projection(projection);
// 人口の最大値,最小値,中央値の取得
var max = d3.max(json.features,function(a){return a.properties.JINKO;})
var min = d3.min(json.features,function(a){return a.properties.JINKO;})
var median = d3.median(json.features,function(a){return a.properties.JINKO;})
// 塗り色で人口を表現するための正規化関数の定義
var colorScale = d3.scale.linear()
.domain([min,median,max])
.interpolate(d3.interpolateRgb).range(["#FFFFFF", "#FFFF00","#FF0000"]);
// 描画
svg.selectAll('path').data(json.features).enter()
.append('path')
.attr('d', path)
.attr("fill", function(d){ return colorScale(d.properties.JINKO);})
.attr("stroke",d3.rgb(0,0,0) )
.on('mouseover', function(d){ /* mouseover event */ })
.on('mouseout', function(d){ /* mouseout event */ })
// clickイベントで呼び出される関数を設定
.on('click', function(d) {alert(d.properties.MOJI); });
});
};
マウスオーバ,マウスアウト時に 塗り色を変更する場合は例えば以下のように変更します.
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
var svg = d3.select("#screen")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
// GeoJSONデータの読み込み
d3.json("kunitachi.json", function(json) {
var projection,path;
// 投影関数定義(メルカトル図法)
projection = d3.geo.mercator()
.center(d3.geo.centroid(json))
.translate([width / 2, height / 2])
.scale(450000);
// 投影方法設定
path = d3.geo.path().projection(projection);
// 人口の最大値,最小値,中央値の取得
var max = d3.max(json.features,function(a){return a.properties.JINKO;})
var min = d3.min(json.features,function(a){return a.properties.JINKO;})
var median = d3.median(json.features,function(a){return a.properties.JINKO;})
// 塗り色で人口を表現するための正規化関数の定義
var colorScale = d3.scale.linear()
.domain([min,median,max])
.interpolate(d3.interpolateRgb).range(["#FFFFFF", "#FFFF00","#FF0000"]);
// 描画
svg.selectAll('path').data(json.features).enter()
.append('path')
.attr('d', path)
.attr("fill", function(d){ return colorScale(d.properties.JINKO);})
.attr("stroke",d3.rgb(0,0,0,255) )
// mouseover時は青色に変更
.on('mouseover', function(d){ d3.select(this).attr("fill",d3.rgb(0,0,255));})
// mouseout時に塗り色を元にもどす
.on('mouseout', function(d){ d3.select(this).attr("fill",colorScale(d.properties.JINKO));})
.on('click', function(d) {alert(d.properties.MOJI); });
});
};
今度は d3.js + leaflet の組合せで GeoJSON を地図上にマッピングします. leaflet は GeoJSON をサポートしているので d3.js 単体で表示するよりも簡単に表示できてしまいます.
地図をクリックしたときにPopupを表示するのも簡単に実現できます.
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
d3.select("#screen").attr("id","map").attr("style", "width: "+width+"px; height: "+height+"px;");
// 地図の描画
var map = L.map('map').setView([35.70089,139.4300], 14);
var credit = '<a href="http://portal.cyberjapan.jp/help/termsofuse.html">国土地理院</a>';
var tileurl = 'http://cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png';
L.tileLayer(tileurl, {maxZoom: 18, attribution: credit,}).addTo(map);
// GeoJSONの読み込み
d3.json("kunitachi.json", function(json) {
// 人口の最大値,最小値,中央値の取得
var max = d3.max(json.features,function(a){return a.properties.JINKO;})
var min = d3.min(json.features,function(a){return a.properties.JINKO;})
var median = d3.median(json.features,function(a){return a.properties.JINKO;})
// 塗り色で人口を表現するための正規化関数の定義
var colorScale = d3.scale.linear()
.domain([min,median,max])
.interpolate(d3.interpolateRgb)
.range(["#FFFFFF", "#FFFF00","#FF0000"]);
// 線の色、塗り色の設定
new L.GeoJSON(json, { style: function(feature) {
return {color: '#000000','fillColor': colorScale(feature.properties.JINKO), 'fillOpacity': 0.5};
},
// popupの登録
onEachFeature: function (feature, layer) {
layer.bindPopup(feature.properties.MOJI+"<br/>人口:"+feature.properties.JINKO);
}}).addTo(map);
});
};
今度は国単位でのシェープファイルの表示を行ってみましょう.
GADM database of Global Administrative Areas にアクセスします.ここでは国単位でのシェープファイルをダウンロードすることができます.
GADM database of Global Administrative Areas(http://www.gadm.org/)
画面上部にあるタブ「Download」をクリックします.
Countryを「Japan」、File Formatを「Shapefile」とします.(余談ですが R フォーマットでの入手も可能です)
OKをクリックします.
日本地図が表示されるので,下方にある「Download」のリンクをクリックします.シェープファイルのダウンロードが開始されます.ファイル名は「JPN_adm_shp.zip」となります.
先程はシェープファイルの変換に R を使いましたが,今回はウェブサービス「mapshaper」を利用します.下記アドレスにアクセスしてください.
mapshaper(http://www.mapshaper.org/)
「select」ボタンをクリックし,先ほどダウンロードしたシェープファイル(zip形式のまま)を選択します.
シェープファイルを選択できたら「Import」をクリックします。
下記のような画面が表示されます.エラーが表示されていなければ読み込み成功です.
画面上部にある「JPN_adm0」(この表示はシェープファイルの内容により変わります)をクリックします.するとレイヤー一覧が表示されます.レイヤーをクリックすると選択されたレイヤーが画面に表示されます.
レイヤーの一覧から「data records」とあるレイヤーを削除します.「X」ボタンをクリックするとそのレイヤーを削除することができます.
画面右上部の「Export」をクリックします.
レイヤー「JPN_adm0」のみを選択状態とします.ファイルフォーマットは「GeoJSON」とし,「Export」をクリックします.
これでシェープファイルをGeoJSONフォーマットに変換することができました.
ファイル名を「JPN_adm0.geojson」に変更します.
「mapshaper」はまだ利用するので閉じないでおいてください.
つぎにTopoJSONと呼ばれるGeoJSON拡張フォーマットへの変換を行います.TopoJSONはGeoJSONと比較してファイルサイズが小さくなるという利点があります.
先程の「mapshaper」の画面に戻り,「Export」をクリック,「Export Menu」のレイヤーを「JPN_adm0」のみ,ファイルフォーマットを「TopoJSON」とし,「Export」をクリックします.
ファイルがダウンロードできたら, ファイル名を「JPN_adm0.topojson」に変更します.
「mapshaper」は情報を簡素化する機能も備えています.簡素化により,地理情報の正確性は失われますが,ファイルサイズを小さくすることができます.
「Simplify」をクリックします.
「Apply」をクリックします.
ゲージを操作し,簡素化レベルを変更します.
あとは好みのファイルフォーマットで「Export」するだけで簡素化されたファイルが出力されます.
ウェブでの利用で精度が要求されることは殆どないので, 簡素化してからGeoJSON or TopoJSONで出力したほうがよいでしょう.
さっそく変換したしたGeoJSONファイルをd3jsで可視化してみましょう.
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
var svg = d3.select("#screen")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
// GeoJSONデータの読み込み
d3.json("JPN_adm0.geojson", function(json) {
var projection,path;
// 投影関数定義(メルカトル図法)
projection = d3.geo.mercator()
.center(d3.geo.centroid(json))
.translate([width / 2, height / 2])
.scale(1000);
// 投影方法設定
path = d3.geo.path().projection(projection);
// 描画
svg.selectAll('path').data(json.features).enter()
.append('path')
.attr('d', path)
.attr("stroke",d3.rgb(0,0,0));
});
};
GeoJSONファイルのサイズが大きい場合は読み込みまでに時間がかかります.
TopoJSONを読み込むには d3.js 用のプラグインが必要になります.
http://d3js.org/topojson.v2.min.js
上記URLをhtmlファイルに追加します.
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ひな形HTMLファイル</title>
<!-- d3.jsライブラリの読み込み -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<!-- topojson plugin -->
<script src="http://d3js.org/topojson.v2.min.js"></script>
<!-- leaflet -->
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet/v1.0.2/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet/v1.0.2/leaflet.js"></script>
<!-- スタイルシート -->
<link rel="stylesheet" href="style.css" type="text/css" />
<!-- 処理用スクリプト -->
<script type="text/javascript" src="script.js" ></script>
</head>
<body onload="init();">
<div id="screen"></div>
</body>
</html>
d3.js でtopojsonを表示するためにscipt.jsを以下のように変更します.
/* onloadで呼び出される関数 */
function init(){
var width = window.innerWidth;
var height = window.innerHeight;
var svg = d3.select("#screen")
.append("svg")
.attr("width", width)
.attr("height", height)
.append("g");
// TopoJSONデータの読み込み
d3.json("JPN_adm0.topojson", function(json) {
// GeoJSONへ変換(JPN_adm0はレイヤー名)
var geojson = topojson.feature(json,json.objects.JPN_adm0);
var projection,path;
// 投影関数定義(メルカトル図法)
projection = d3.geo.mercator()
.center(d3.geo.centroid(geojson))
.translate([width / 2, height / 2])
.scale(1000);
// 投影方法設定
path = d3.geo.path().projection(projection);
// 描画
svg.selectAll('path').data(geojson.features).enter()
.append('path')
.attr('d', path)
.attr("stroke",d3.rgb(0,0,0));
});
};
大きな違いはtopojson.feature関数でTopoJSON形式をGeoJSON形式に変換している点です.
ちなみに下記は「mapshaper」で簡素化した(10%)データを表示したものです.
もっと簡素化してもよさそうですね.
課題を解き,使用したGeoJSONファイル(またはTopoJSONファイル)およびスクリプトを提出してください.
e-Statより「平成22年国勢調査(小地域)2010/10/01」のシェープファイルを入手し(国立以外ならどこでもよい),d3.js + leaflet の組合せで地図上にマッピングしてください.
e-Statより「平成22年国勢調査(小地域)2010/10/01」のシェープファイルおよび統計データ「年齢別(5歳階級、4区分)、男女別人口」を入手し(国立以外ならどこでもよい),「地域別高齢者(65歳以上)人口比率」がみえるように d3.js + leaflet の組合せで可視化してください.
e-Statより「平成22年国勢調査(小地域)2010/10/01」のシェープファイルおよび統計データ「年齢別(5歳階級、4区分)、男女別人口」を入手し(国立以外ならどこでもよい),「地域別高齢者(65歳以上)人口比率」がみえるように d3.js のみで可視化してください.
e-statから取得した統計GISデータを 加工し,シェープファイルとして保存します.これによりGeoJSON or TopoJSON変換時に利用可能な属性情報を追加・加工・削除することができます.
たとえば,
if(!require(maptools)){
install.packages("maptools");
library(maptools);
}
if(!require(dplyr)){
install.packages("dplyr");
library(dplyr);
}
# シェープファイルを読み込む
shp<-maptools::readShapePoly("A002005212010DDSWC13215/h22ka13215.shp")
# shp@data$KEY_CODEを数値にする
shp@data$KEY_CODE<-as.numeric(as.character(shp@data$KEY_CODE))
# CSVファイルを読み込む
csv<-read.csv("tblT000573C13215.txt",stringsAsFactors = FALSE,fileEncoding = "SJIS")
# 不要な1行目(日本語の説明)を削除する
csv <- csv[-1,]
# shp@dataとcsvをKEY_CODEをキーに結合する
shp@data<-dplyr::inner_join(shp@data,csv,by="KEY_CODE")
# shp@data$T000573019を数値にする
shp@data$T000573019 <- as.numeric(as.character(shp@data$T000573019))
# shp@dataにRATE列を追加
shp@data$RATE <- shp@data$T000573019/shp@data$JINKO
# 日本語をUTF8にする
shp@data$MOJI <- iconv(shp@data$MOJI,from="sjis",to="utf8")
shp@data$GST_NAME <- iconv(shp@data$GST_NAME,from="sjis",to="utf8")
shp@data$KEN_NAME <- iconv(shp@data$KEN_NAME,from="sjis",to="utf8")
# 不要なデータを削除する
shp@data$DUMMY1 <- NULL
# シェープファイルを書き出す
maptools::writePolyShape(shp,"tmp/kunitachi2")
Masaharu Hayashi を著作者とするこの 作品 は クリエイティブ・コモンズの 表示 4.0 国際 ライセンスで提供されています。